const  REFERENCE_YEAR : i32 = 2024;
const REFERENCE_WEEKDAY: i32 = 1; // Jan 1, 1,Monday

pub fn time_info(time: &str) -> String {
    let (year, month, day) = parse_date(time);
    let week_num = week_info(year, month, day);
    let remaining_days = remaining_days(year, month, day);

    let mut time_solar = SolarT::new(year, month, day);
    let nearest_lunar_first = get_nearest_lunar_first_day(&time_solar);
    let mut date_interval = time_solar.date_interval(&nearest_lunar_first)-2;
    if date_interval < 0 {
        time_solar.add_one_day();
        let nearest_lunar_first_temp = get_nearest_lunar_first_day(&time_solar);
        date_interval = time_solar.date_interval(&nearest_lunar_first_temp)-1;
    }
    format!("{},{},{}", week_num, remaining_days, date_interval)
}

fn is_leap(year: i32) -> bool {
    (year % 4 == 0 && year % 100!= 0) || year % 400 == 0
}

fn days_in_year(year: i32) -> i32 {
    if is_leap(year) { 366 } else { 365 }
}

fn days_in_month(year: i32, month: i32) -> i32 {
    match month{
        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
        4 | 6 | 9 | 11 => 30,
        2 => if is_leap(year) { 29 } else { 28 },
        _ => panic !("Invalid month"),
    }
}

fn parse_date(date_str: &str) -> (i32, i32, i32) {
    let parts: Vec<&str> = date_str.split('-').collect();
    if parts.len()!= 3 {
        panic!("Invalid date format");
    }

    let year = parts[0].parse::<i32>().unwrap();
    let month = parts[1].parse::<i32>().unwrap();
    let day = parts[2].parse::<i32>().unwrap();

    (year, month, day)
}

//return weekday number (1-7)
fn first_day_info(target_year: i32) -> i32 {
    let mut weekday = REFERENCE_WEEKDAY;
    let mut year = REFERENCE_YEAR;

    while year < target_year {
        weekday = (weekday + if is_leap(year) { 2 } else { 1 }) % 7;
        year += 1;
    }

    while year > target_year {
        year -= 1;
        weekday = (weekday - if is_leap(year) { 2 } else { 1 }+7) % 7;
    }
    weekday
}

fn date_to_ordinal(year: i32, month: i32, day: i32) -> i32 {
    let mut ordinal = day;
    for m in 1..month {
        ordinal += days_in_month(year, m);
    }
    ordinal
}

fn week_info(target_year: i32, target_month: i32, target_day: i32) -> i32 {
    let this_first_weekday = first_day_info(target_year);
    let nxt_first_weekday = first_day_info(target_year+1);
    let ordinal = date_to_ordinal(target_year, target_month, target_day);

    if 7 - this_first_weekday + 1 >= ordinal {
        if this_first_weekday <= 4 {
            return 1;
        }
        else{
            return week_info(target_year-1, 12, 28);  
        }
    }
    else if days_in_year(target_year) + 1 - nxt_first_weekday + 1 <= ordinal  {
        if nxt_first_weekday <= 4 {
            return 1;
        }
        else{
            if this_first_weekday <= 4 {
                let week_num = 1+ ((ordinal - (7 - this_first_weekday + 1)) -1) / 7 +1;
                return week_num;
            }
            else {
                return  ((ordinal - (7 - this_first_weekday + 1)) -1) / 7 +1;
            }
        }
    }
    else{
        if this_first_weekday <= 4 {
            let week_num = 1+ ((ordinal - (7 - this_first_weekday + 1)) -1) / 7 +1;
            return week_num;
        }
        else {
            return  ((ordinal - (7 - this_first_weekday + 1)) -1) / 7 +1;
        }
    }
}

fn remaining_days(target_year: i32, target_month: i32, target_day: i32) -> i32 {
    let ordinal = date_to_ordinal(target_year, target_month, target_day);
    let days_in_target_year = days_in_year(target_year);

    days_in_target_year - ordinal 
}



//--------------------SolarT to LunarT----------------------------//
/**
 * NongLin data from hongkong observatory
 * bit[3:0] :0 - C. 0 means there is no leap month in this year,
 *  non-zero means there is a leap month in this year, 
 * and the specific value 1 - C represents the leap month
 * bit [15:4] bit 15 - bit 4 represent January - December of this year respectively, 
 * 0 means this month is a short month (29 days), 
 * 1 means a long month (30 days)
 * bit16 is ignored when bit [3:0] is 0;
 * its value is only valid when bit [3:0] is not 0, 1 means the leap month of this year is a long month,
 *  0 means a short month
 */

const NONGLI_INFO:[i32; 201] = 
[
    0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909
    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919
    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929
    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939       
    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949
    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959
    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969
    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, //1970-1979
    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989
    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999       
    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009
    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019
    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029
    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039
    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049
    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059       
    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069       
    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079
    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089
    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099
    0x0d520                                                                                   //2100
];

struct SolarT {
    year: i32,
    month: i32,
    day: i32,
}

impl SolarT {
    fn new(year: i32, month: i32, day: i32) -> SolarT {
        SolarT {
            year: year,
            month: month,
            day: day,
        }
    }

    fn date_interval(&self,other: &Self) -> i32 {
        // other - self 
        let mut res = 0;
        let ordinal1 = date_to_ordinal(self.year, self.month, self.day);
        let ordinal2 = date_to_ordinal(other.year, other.month, other.day);
        let mut temp_year = self.year.clone();
        
        res += (ordinal2 - ordinal1) as i32;

        while temp_year < other.year {
            res += days_in_year(temp_year);
            temp_year += 1;
        }
        
        res
    }

    fn add_one_day(&mut self) {
        self.day += 1;
        if self.day > days_in_month(self.year, self.month){
            self.day = 1;
            self.month += 1;
        }
        if self.month > 12 {
            self.year += 1;
            self.month = 1;
        }
    }
}

struct LunarT {
    solar_year: i32,
    has_leap_month: bool,
    leap_month: i32,               
    leap_month_30days : bool,

    month : i32,
    is_leap_month: bool,
    date: i32,
    animal: i32,
    tian_gan: i32,
    di_zhi: i32,
}

#[allow(while_true)]
impl LunarT {
    fn new(solar_year: i32) -> LunarT {
        // standard LunarT : 1900/1/31 正月初一，鼠年
        let lunar = LunarT {
            solar_year: solar_year,
            has_leap_month: false,
            leap_month: 0,
            leap_month_30days: false,
            month: 1,
            is_leap_month: false,
            date: 1,
            animal: 1,
            tian_gan: 7,
            di_zhi: 1,
        };

        lunar
    }

    fn leap_month_by_year(&mut self)  {
        assert!(self.solar_year >= 1900 && self.solar_year <= 2100);

        if NONGLI_INFO[(self.solar_year-1900) as usize ] & 0x0f == 0 || NONGLI_INFO[(self.solar_year-1900) as usize] & 0x0f > 12{
            self.has_leap_month = false;
        } else {
            self.has_leap_month = true;
            self.leap_month = NONGLI_INFO[(self.solar_year-1900) as usize] & 0x0f;
            self.leap_month_30days = (NONGLI_INFO[(self.solar_year-1900) as usize] >> 16) & 0x01 == 1;
        }

    }

    fn new_from_solar_date(&mut self , solar_date_interval: i32) -> LunarT {
        let mut solar_year = 1900;
        let mut date_interval_temp = 0;
        let mut lunar = LunarT::new(1900);

        while true {
            lunar.leap_month_by_year();

            if lunar.is_leap_month {
                date_interval_temp += if lunar.leap_month_30days  {30} else {29};
            }
            else {
                date_interval_temp += lunar_month_days_nums(solar_year, lunar.month);
            }

            if date_interval_temp >= solar_date_interval {
                if lunar.is_leap_month {
                    lunar.date = (if lunar.leap_month_30days  {30} else {29}) - (date_interval_temp - solar_date_interval);
                }
                else {
                    lunar.date = lunar_month_days_nums(solar_year, lunar.month) - (date_interval_temp - solar_date_interval);
                }

                break;
            }

            if lunar.has_leap_month && !lunar.is_leap_month {
                if lunar.leap_month == lunar.month {
                    lunar.is_leap_month = true;
                }
                else {
                    lunar.month += 1;
                }
            } 

            else if (lunar.has_leap_month && lunar.is_leap_month) || (!lunar.has_leap_month ){
                lunar.is_leap_month = false;
                lunar.month += 1;
            }

            if lunar.month > 12 {
                solar_year += 1;
                lunar.solar_year = solar_year;
                lunar.month = 1;
                lunar.animal += 1;
                if lunar.animal > 12 {
                    lunar.animal = 1;
                }
                lunar.tian_gan += 1;
                if lunar.tian_gan > 10{
                    lunar.tian_gan = 1;
                }
            }
            lunar.di_zhi = lunar.animal;
        }
        lunar
    }
}

// 非闰月天数
fn lunar_month_days_nums(solar_year: i32, lunar_month: i32) -> i32 {
    if lunar_month < 1 || lunar_month > 12 {
        return -1;
    }

    if  (NONGLI_INFO[(solar_year - 1900) as usize] >> ((12 - lunar_month) + 4) ) & 0x00000001 == 1 {
        return 30;
    }
    else {
        return 29;
    }

}

fn solar_to_lunar(solar_date: &SolarT) -> LunarT {
    let mut lunar = LunarT::new(1900);
    let solar_1900 = SolarT::new(1900, 1, 31);
    lunar.new_from_solar_date(solar_1900.date_interval(solar_date))
}

fn get_nearest_lunar_first_day(solar_date: &SolarT) -> SolarT {
    let mut result = SolarT::new(solar_date.year, solar_date.month, solar_date.day);
    if (solar_to_lunar(&result).month == 1  && solar_to_lunar(&result).date == 1) || (solar_to_lunar(&result).month == 1  && solar_to_lunar(&result).date == 2){
        result.add_one_day();
    }
    while solar_to_lunar(&result).month != 1  || solar_to_lunar(&result).date != 1 {
        result.add_one_day();
    }   
    result
}